import { EMPTY_LOG_FILTER } from "@/_test/constants.js";
import type { LogFactory, LogFilter } from "@/internal/types.js";
import type { Hex } from "viem";
import { expect, test } from "vitest";
import { isFilterInBloom, isInBloom } from "./bloom.js";

test("isInBloom", () => {
  let bloom =
    "0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" as Hex;

  const address = "0xef2d6d194084c2de36e0dabfce45d046b37d1106";
  let topic =
    "0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc" as Hex;

  expect(isInBloom(bloom, address)).toBe(true);
  expect(isInBloom(bloom, topic)).toBe(true);

  bloom =
    "0x00000000000000000000008000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000044000200000000000000000002000000000000000000000040000000000000000000000000000020000000000000000000800000000000800000000000800000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808002000000000400000000000000000000000060000000000000000000000000000000000000000000000100000000000002000000" as Hex;

  expect(isInBloom(bloom, address)).toBe(false);
  expect(isInBloom(bloom, topic)).toBe(false);

  topic =
    "0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb" as Hex;

  expect(isInBloom(bloom, topic)).toBe(true);
});

test("isFilterInBloom returns false for out of range blocks", () => {
  const block = {
    number: "0x5",
    logsBloom:
      "0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  } as const;

  const filter = {
    ...EMPTY_LOG_FILTER,
    fromBlock: 10,
    toBlock: 20,
  } satisfies LogFilter;

  expect(isFilterInBloom({ block, filter })).toBe(false);
});

test("isFilterInBloom returns false for missing topics", () => {
  const block = {
    number: "0x5",
    logsBloom:
      "0x00000000000000000000008000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000044000200000000000000000002000000000000000000000040000000000000000000000000000020000000000000000000800000000000800000000000800000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808002000000000400000000000000000000000060000000000000000000000000000000000000000000000100000000000002000000",
  } as const;

  const filter = {
    ...EMPTY_LOG_FILTER,
    topic0:
      "0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc",
  } satisfies LogFilter;

  expect(isFilterInBloom({ block, filter })).toBe(false);
});

test("isFilterInBloom returns true for undefined address", () => {
  const block = {
    number: "0x5",
    logsBloom:
      "0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  } as const;

  const filter: LogFilter = {
    ...EMPTY_LOG_FILTER,
    // @ts-expect-error
    topic0: undefined,
  };

  expect(isFilterInBloom({ block, filter })).toBe(true);
});

test("isFilterInBloom returns true for factory with new child address", () => {
  const block = {
    number: "0x5",
    logsBloom:
      "0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  } as const;

  const filter = {
    ...EMPTY_LOG_FILTER,
    address: {
      id: `log_${"0xef2d6d194084c2de36e0dabfce45d046b37d1106"}_${1}_topic${1}_${"0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc"}_${"undefined"}_${"undefined"}`,
      type: "log",
      chainId: 1,
      sourceId: "factory",
      address: "0xef2d6d194084c2de36e0dabfce45d046b37d1106",
      eventSelector:
        "0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc",
      childAddressLocation: "topic1",
      fromBlock: undefined,
      toBlock: undefined,
    } satisfies LogFactory,
  } satisfies LogFilter;

  expect(isFilterInBloom({ block, filter })).toBe(true);
});

test("isFilterInBloom returns true for factory without new child address", () => {
  const block = {
    number: "0x5",
    logsBloom:
      "0x00000000000000000000008000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000044000200000000000000000002000000000000000000000040000000000000000000000000000020000000000000000000800000000000800000000000800000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808002000000000400000000000000000000000060000000000000000000000000000000000000000000000100000000000002000000",
  } as const;

  const filter = {
    ...EMPTY_LOG_FILTER,
    address: {
      id: `log_${"0xef2d6d194084c2de36e0dabfce45d046b37d1106"}_${1}_topic${1}_${"0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc"}_${"undefined"}_${"undefined"}`,
      type: "log",
      chainId: 1,
      sourceId: "factory",
      address: "0xef2d6d194084c2de36e0dabfce45d046b37d1106",
      eventSelector:
        "0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc",
      childAddressLocation: "topic1",
      fromBlock: undefined,
      toBlock: undefined,
    } satisfies LogFactory,
    topic0:
      "0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb",
  } satisfies LogFilter;

  expect(isFilterInBloom({ block, filter })).toBe(true);
});

test("isFilterInBloom returns true for array of addresses", () => {
  const block = {
    number: "0x5",
    logsBloom:
      "0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  } as const;

  const filter: LogFilter = {
    ...EMPTY_LOG_FILTER,
    address: ["0xef2d6d194084c2de36e0dabfce45d046b37d1106"],
    // @ts-expect-error
    topic0: undefined,
  };

  expect(isFilterInBloom({ block, filter })).toBe(true);
});
